﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using matrix = Microsoft.Xna.Framework.Matrix;

namespace XnaCanvas {
    public abstract class XObject {
        protected VertexBuffer vbuffer;
        protected IndexBuffer ibuffer;
        public BasicEffect effect;
        public virtual matrix World { get; set; }
        protected int primitiveCountType;
        private PrimitiveType primitivTypemy;
        public PrimitiveType PrimitivType {
            get { return primitivTypemy; }
            set {
                primitivTypemy = value;
                switch (value) {
                    case PrimitiveType.LineList:
                        primitiveCountType = 2;
                        break;
                    case PrimitiveType.LineStrip:
                        primitiveCountType = 2;
                        break;
                    case PrimitiveType.TriangleList:
                        primitiveCountType = 3;
                        break;
                    case PrimitiveType.TriangleStrip:
                        primitiveCountType = 3;
                        break;
                    default:
                        break;
                }
            }
        }
        //
        internal XSence xsence;
        protected Vector4 XColor { get; set; }
        public void SetColor(float r, float g, float b, float a) {
            this.XColor = new Vector4(r, g, b, a);
        }
        protected XObject() {
            this.effect = new BasicEffect(XSence.Device);
            this.effect.VertexColorEnabled = true;
            this.World = matrix.Identity;
        }
        protected bool isDynamicIV;
        public abstract void Present();

        internal protected List<VertexPositionNormalColor> vertices;
        public void AddVertex(Vector3 pos, Vector3 normal, Vector4? color = null) {
            var color2 = color;
            color2 = color ?? this.XColor;
            vertices.Add(new VertexPositionNormalColor(pos, normal, color2.Value));
        }
        public void AddVertex(Vector2 pos, Vector3 normal, Vector4? color = null) {
            var color2 = color;
            color2 = color ?? this.XColor;
            vertices.Add(new VertexPositionNormalColor(new Vector3(pos.X, pos.Y, 0), normal, color2.Value));
        }
        public void ClearVertex() {
            vertices.Clear();
        }
        protected List<ushort> indices;
        public void AddIndex(int i) {
            indices.Add((ushort)i);
        }
        public void ClearIndex() {
            indices.Clear();
        }
        public int IndexCount { get { return indices.Count; } }
        public virtual void SetData() {
            OnLoaded();
            if (vbuffer == null&&vertices.Count > 0) {
                if (this.isDynamicIV) {
                    this.vbuffer = new DynamicVertexBuffer(XSence.Device, typeof(VertexPositionNormalColor), vertices.Count, BufferUsage.None);
                } else {
                    this.vbuffer = new VertexBuffer(XSence.Device, typeof(VertexPositionNormalColor), vertices.Count, BufferUsage.None);
                }
                vbuffer.SetData(vertices.ToArray());
                primitiveCount = vertices.Count / primitiveCountType;
            } 
            if (ibuffer == null && indices.Count > 0) {
                if (this.isDynamicIV) {
                    this.ibuffer = new DynamicIndexBuffer(XSence.Device, IndexElementSize.SixteenBits, indices.Count, BufferUsage.None);
                } else {
                    this.ibuffer = new IndexBuffer(XSence.Device, IndexElementSize.SixteenBits, indices.Count, BufferUsage.None);
                }
                ibuffer.SetData(indices.ToArray());
                primitiveCount = indices.Count / primitiveCountType;
            } else if (indices.Count > 0) {
                ibuffer.SetData(indices.ToArray());
                primitiveCount = indices.Count / primitiveCountType;
            }
        }
        protected int primitiveCount;
        public virtual void ClearBuffer() {
            this.World = matrix.Identity;
            vertices.Clear();
            indices.Clear();
            OnUnLoaded();
        }
        /// <summary>
        /// 每个顶点进行变换(位置和法线)
        /// </summary>
        /// <param name="transform"></param>
        public void Transform(matrix transform) {
            for (int i = 0; i < vertices.Count; i++) {
                vertices[i] = vertices[i].Transform(transform);
            }
            SetData();
        }
        public event EventHandler Loaded;
        internal protected virtual void OnLoaded() {
            if (this.Loaded != null) {
                this.Loaded.Invoke(this, EventArgs.Empty);
            }
        }
        public event EventHandler UnLoaded;
        internal protected virtual void OnUnLoaded() {
            if (this.UnLoaded != null) {
                this.UnLoaded.Invoke(this, EventArgs.Empty);
            }
        }
        //
        public static Vector2[] Get2(params float[] ps) {
            if (ps.Length < 2 || ps.Length % 2 != 0) {
                throw new Exception("值不在预期范围,必须是偶数个float");
            }
            var count = ps.Length;
            var vs = new List<Vector2>();
            for (int i = 0; i < count; i+=2) {
                vs.Add(new Vector2(ps[i], ps[i + 1]));
            }
            return vs.ToArray();
        }
        //
        public static Vector3[] Get3(params float[] ps) {
            if (ps.Length < 3 || ps.Length % 3 != 0) {
                throw new Exception("值不在预期范围,必须是整除3个float");
            }
            var count = ps.Length;
            var vs = new List<Vector3>();
            for (int i = 0; i < count; i+=3) {
                vs.Add(new Vector3(ps[i], ps[i + 1], ps[i + 2]));
            }
            return vs.ToArray();
        }
        //
        public static Vector4[] Get4(params float[] ps) {
            if (ps.Length < 4 || ps.Length % 4 != 0) {
                throw new Exception("值不在预期范围,参数个数必须整除4");
            }
            var count = ps.Length;
            var vs = new List<Vector4>();
            for (int i = 0; i < count; i+=4) {
                vs.Add(new Vector4(ps[i], ps[i + 1], ps[i + 2], ps[i + 3]));
            }
            return vs.ToArray();
        }
    }
}
